{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "<table>\n",
    " <tr align=left><td><img align=left src=\"./images/CC-BY.png\">\n",
    " <td>Text provided under a Creative Commons Attribution license, CC-BY. All code is made available under the FSF-approved MIT license. (c) Kyle T. Mandli</td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function, division"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "Note to lecturers:  This notebook is designed to work best as a classic Jupyter Notebook with nbextensions \n",
    "* hide_input: to hide selected python cells particularly for just plotting\n",
    "* RISE:  Interactive js slide presentations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Discussion 1:  Introduction to Python\n",
    "\n",
    "So you want to code in Python?  We will do some basic manipulations and demonstrate some of the basics of the notebook interface that we will be using extensively throughout the course."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Topics:\n",
    " - Math\n",
    " - Variables\n",
    " - Lists\n",
    " - Control flow\n",
    " - Coding style\n",
    " - Other data structures\n",
    " - IPython/Jupyter notebooks\n",
    "   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "There is considerable online documentation and tutorials for python.\n",
    "\n",
    "### Other intros: \n",
    " - [Basic Python](https://docs.python.org/2/tutorial/introduction.html)\n",
    " - [Software Carpentry - Programming in Python](http://swcarpentry.github.io/python-novice-inflammation/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Python Math\n",
    "\n",
    "Lets start with some basic operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "2 + 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "32 - (4 + 2)**2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "1 / 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "4.0 + 4.0**(3.0 / 2.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Good practice to just add a decimal after any number you really want to treat as a `float`.\n",
    "\n",
    "Additional types of numbers include `complex`, `Decimal` and `Fraction`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "3+5j"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Note that to use \"named\" functions such as `sqrt` or `sin` we need to `import` a module so that we have access to those functions.  When you `import` a module (or package) in Python we are asking Python to go look for the code that is named and make them active in our workspace (also called a namespace in more general parlance).  Here is an example where we use Python's builtin `math` module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import math\n",
    "math.sqrt(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "math.sin(math.pi / 2.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "math.exp(-math.pi / 4.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Note that in order to access these functions we need to prepend the `math.` to the functions and the constant $\\pi$.  We can forgo this and import all of what `math` holds if we do the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from math import *\n",
    "sin(pi / 2.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Notes:\n",
    "* `import *` is discouraged, particularly if you only need a few functions or you will be mixing with other modules that define `sin`,  for example `numpy.sin()` and `math.sin()` have somewhat different functionality.\n",
    "* if you only want a few functions from math use\n",
    "    `from math import sin, cos`\n",
    "* many of these functions always return a `float` number regardless of their input.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Variables\n",
    "\n",
    "Assign variables like you would in any other language:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "num_students = 80\n",
    "room_capacity = 85\n",
    "(room_capacity - num_students) / room_capacity * 100.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "As indicated in the previous section, there are many different data types. For example, a variable could be an integer, a floating point number, a string, or numerous other basic types. Python will determine the data type based on how you enter it. \n",
    "\n",
    "In the following example, three different variables are defined, and the type associated with each variable is printed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "number = 5\n",
    "ratio = 0.15\n",
    "description = \"The ratio is\"\n",
    "doit = False\n",
    "print(number,type(number))\n",
    "print(ratio,type(ratio))\n",
    "print(description,type(description))\n",
    "print(doit,type(doit))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "The data type can be explicitly defined using the float() and int() commands."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "number = int(5)\n",
    "ratio = float(0.15)\n",
    "print(number,type(number))\n",
    "print(ratio,type(ratio))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Note:  if you are testing for the type of a python object you should use `isinstance`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "x = 'howdy'\n",
    "if isinstance(x,str):\n",
    "    print('{} is a string'.format(x))\n",
    "else:\n",
    "    print('{} is not a string'.format(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "One thing to be careful about is that Python is case sensitive."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "N = 20\n",
    "n = 10\n",
    "print(N,n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Lists\n",
    "\n",
    "One of the most useful data structures in Python is the `list`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "grades = [90.0, 67.0, 85.0, 76.0, 98.0, 70.0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Lists are defined with square brackets and delineated by commas.  Note that there is another data type called `sequences` denoted by `( )` which are immutable (cannot be changed) once created.  Lets try to do some list manipulations with our list of grades above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Access a single value in a list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "print(grades)\n",
    "grades[3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Note that Python is 0 indexed, i.e. the first value in the list is accessed by `0`. Reverse indexing is done using negative value starting from -1 which corresponds to the last element"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "grades[-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Find the length of a list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "len(grades)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "There are multiple ways to append values into a list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "print(grades)\n",
    "grades = grades + [62.0, 82.0, 59.0]\n",
    "print(grades)\n",
    "grades.append(88.0)\n",
    "print(grades)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "You can use the standard indexing method shown above to change a value within the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "grades[1] = 68.0\n",
    "print(grades)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Slicing is another important operation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "grades[2:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "grades[0:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "grades[:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "grades[4:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Note that the range of values does not include the last indexed!  This is important to remember for more than lists but we will get to that later."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "grades[4:11]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Another property of lists is that you can put different types in them at the same time.  This can be important to remember if you may have both `int` and `float` types."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "remember = [int(\"2\"), 2, 2.0, \"2.0\"]\n",
    "print(remember)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "A list can also hold any data type or data structure inside it, for example a list inside a list (referred to as nested lists) is helpful in defining matrices (although we will find a better way to do this later)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "matrix_a = [[1],[2],[3]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "remember[0] / 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "remember[1] / 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "remember[2] / 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Finally, one of the more useful list creation functions is `range` which creates a list with the bounds requested. This creates a special type within Python, but it acts like an array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "values = range(3,7)\n",
    "print(values,type(values))\n",
    "print(values[0],values[1],values[2])\n",
    "for i in range(3, 7):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Comments\n",
    "\n",
    "Comments can be added to code using the `#` character. Anything after `#` on a line is ignored."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Set up the parameters associated with the partition\n",
    "N = 10                  # Number of partitions to use\n",
    "b = 1.0                 # The right endpoint of the interval\n",
    "a = 0.0                 # The left endpoint of the interval\n",
    "deltaX = (b-a)/float(N) # The width of each interval\n",
    "print(\"The interval width is {0}\".format(deltaX))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "The python style guide [PEP 8](http://www.python.org/dev/peps/pep-0008) however discourages in-line comments "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Control Flow\n",
    "         \n",
    "In this section a number of different ways to control and define which commands are executed are given. The commands include conditional expressions like 'if' blocks that decide individual sets of commands to execute. It also includes 'for' loops which define a sequence of commands to execute in order. Finally, the 'while' loop is given which will loop through a set of commands until some condition is met."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `if`\n",
    "This is the basic logical control. A set of instructions is executed if a given condition is met. Note that Python decides what set of commands to execute based on how the code is indented. The '{' and '}' characters have a very different meaning in Python than in C, C++, or Java.\n",
    "\n",
    "Note: See full list of operators supported in python [here](https://www.tutorialspoint.com/python/python_basic_operators.htm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "x = 5\n",
    "if x > 5:\n",
    "    itsBig = True\n",
    "    print(\"x is greater than 5\")\n",
    "elif x < 5:\n",
    "    itsBig = False\n",
    "    print(\"x is less than 5\")\n",
    "else:\n",
    "    itsBig = not True\n",
    "    print(\"x is equal to 5\")\n",
    "print(\"The value of itsBig is {0}\".format(itsBig))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `for` loops\n",
    "\n",
    "The `for` statements provide the most common type of loops in Python. The idea is that a set of commands will be repeated for a fixed number of times. The command requires a variable that can be iterated over, and each time the loop repeats a new value from the variable is used. For example, if an array is given the `for` loop will iterate over each value within the array. (there is also a `while` construct). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "accumulator = 0\n",
    "for i in range(-10, 5, 3):\n",
    "    accumulator += 1\n",
    "    print(i)\n",
    "print(\"The number of times the loop repeated is {0}\".format(accumulator))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "for i in range(3,7):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "for (i, animal) in enumerate(['cat', 'dog', 'chinchilla']):\n",
    "    if i%2 == 0:\n",
    "        print(i, animal)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "The above can be written in a single line and also save the outputs to a new list, by using list comprehension"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "animal_new = [ animal.capitalize() for animal in ['cat', 'dog', 'chinchilla']]\n",
    "range_new = [ i for i in range(3,7)]\n",
    "print(animal_new, range_new)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### A quick exercise:  \n",
    "\n",
    "do you remember the list remember (which is a list of different types)?  write a one line list comprehension to return a list of types in remember"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your answer here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Related to the `for` statement are the control statements `break` and `continue`.  Ideally we can create a loop with logic that can avoid these but sometimes code can be more readable with judicious use of these statements. This is especially true for `while` loops and separate checks have to be made for iteration counts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "for n in range(2, 10):\n",
    "    is_prime = True\n",
    "    for x in range(2, n):\n",
    "        if n % x == 0:\n",
    "            print(n, 'equals', x, '*', n / x)\n",
    "            is_prime = False\n",
    "            break\n",
    "    if is_prime:\n",
    "        print(\"%s is a prime number\" % (n))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### The `while` Loop\n",
    "\n",
    "The set of commands in a while loop are executed while a given condition is True."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "code_folding": [],
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "top    = 10\n",
    "bottom = 0\n",
    "while (top>bottom):\n",
    "    print(\"top: {0}, bottom: {1}\".format(top,bottom))\n",
    "    top    -= 1\n",
    "    bottom += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "The `pass` statement might appear fairly useless as it simply does nothing but can provide a stub to remember to come back and implement something."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def my_func(x):\n",
    "    # Remember to implement this later!\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### Defining Functions\n",
    "\n",
    "The last statement above defines a function in Python with an argument called `x`.  Functions can be defined and do lots of different things, here are a few examples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def my_print_function(x):\n",
    "    print(x)\n",
    "\n",
    "my_print_function(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def my_add_function(a, b):\n",
    "    return(a + b)\n",
    "\n",
    "my_add_function(3.0, 5.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "A variable can be given a implicit value while defining the function, this value remains unchanged unless user specifies a different value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def my_crazy_function(a, b, c=1.0):\n",
    "    d = a + b**c\n",
    "    return d\n",
    "\n",
    "my_crazy_function(2.0, 3.0), my_crazy_function(2.0, 3.0, 2.0), my_crazy_function(2.0, 3.0, c=2.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def my_other_function(a, b, c=1.0):\n",
    "    return a + b, a + b**c, a + b**(3.0 / 7.0)\n",
    "\n",
    "x = my_other_function(2.0, 3.0, c=2.0)\n",
    "x[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Let's try writing a bit more of a complex (and useful) function.  The Fibonacci sequence is formed by adding the previous two numbers of the sequence to get the next value (starting with `[0, 1]`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def fibonacci(n):\n",
    "    \"\"\"Return a list of the Fibonacci sequence up to n\"\"\"\n",
    "    values = [0, 1]\n",
    "    while values[-1] <= n:\n",
    "        values.append(values[-1] + values[-2])\n",
    "        print(values)\n",
    "    return values\n",
    "\n",
    "fibonacci(100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "There are several other data structures useful in python, you can read more about it and its functions [here](https://docs.python.org/3/tutorial/datastructures.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Exception Handling\n",
    "\n",
    "Python has a very rich syntax for handling errors and exceptions which, if used sparingly can be useful when you want to fail gracefully or give the user more information about where and how a function fails.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "def isstring(x):\n",
    "    \"\"\" function to check if x is a string\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    x : any python object\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    bool\n",
    "        True if x is a string, False otherwise.\n",
    "        \n",
    "    Raises\n",
    "    ------\n",
    "    TypeError\n",
    "        if x is not a string\n",
    "    \"\"\"\n",
    "    if isinstance(x, str):\n",
    "        print('{} is a string'.format(x))\n",
    "        return True\n",
    "    else:\n",
    "        raise TypeError('{} is not a string'.format(x))\n",
    "        return False\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "x = 'howdy'\n",
    "isstring(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "If you want to catch an exception and continue execution you can use the `try`-`except` syntax"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "print(remember)\n",
    "for r in remember:\n",
    "    try:\n",
    "        isstring(r)\n",
    "    except TypeError as err:\n",
    "        print(err)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### help(), ? and `tab` are your friends\n",
    "\n",
    "Use the `help()` function or a `?` at the end of a function to see the respective function's documentation. One could also use tab key to autocomplete and view the list of available functions.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "isstring?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "import numpy \n",
    "x = numpy.array(range(3))\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "x.max?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Coding Style\n",
    "\n",
    "It is very important to write readable and understandable code. This is a practical matter. There are times when you have to go back and make changes to code you have not used in a long time. More importantly, coding is a shared activity, and if your code is not readable then it is not of any use."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Here are a few things to keep in mind while programming in and out of this class, we will work on this actively as the semester progresses as well.  The standard for which Python program are written to is called [PEP 8](http://www.python.org/dev/peps/pep-0008) and contains the following basic guidelines:\n",
    " - Use 4-space indentation, no tabs\n",
    " - Wrap lines that exceed 80 characters\n",
    " - Use judicious use of blank lines to separate out functions, classes, and larger blocks of contained code\n",
    " - Comment!  Also, put comments on their own line when possible\n",
    " - Use `docstrings` (function descriptions)\n",
    " - Use spaces around operators and after commas, `a = f(1, 2) + g(3, 4)`\n",
    " - Name your classes and functions consistently.\n",
    "   - Use `CamelCase` for classes\n",
    "   - Use `lower_case_with_underscores` for functions and variables\n",
    " - When in doubt be verbose with your comments and names of variables, functions, and classes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Peer Review\n",
    "\n",
    "To help all of us learn from each other what coding styles are easier to read we should be doing peer-reviews of the coding portions of the assignments.  After the first asssignment is turned in we will review a general template for code review.  Please be as thorough and helpful as you can!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example: why is this actually a poor piece of code?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "def isstring(x):\n",
    "    \"\"\" function to check if x is a string\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    x : any python object\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    bool\n",
    "        True if x is a string, False otherwise.\n",
    "        \n",
    "    Raises\n",
    "    ------\n",
    "    TypeError\n",
    "        if x is not a string\n",
    "    \"\"\"\n",
    "    if isinstance(x, str):\n",
    "        print('{} is a string'.format(x))\n",
    "        return True\n",
    "    else:\n",
    "        raise TypeError('{} is not a string'.format(x))\n",
    "        return False\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Jupyter Notebooks\n",
    "\n",
    "We will use a lot of Jupyter notebooks in this class for both class notes (what you are looking at now) and for turning in homework.  The Jupyter notebook allows for the inline inclusion of a number of different types of input, the most critical will be\n",
    " - Code (python or otherwise) and\n",
    " - Markdown which includes\n",
    "   - LaTeX,\n",
    "   - HTML, and\n",
    "   - JavaScript.\n",
    "IPython notebooks allow us to organize and comment on our efforts together along with writing active documents that can be modified in-situ to our work.  This can lead to better practice of important ideas such as reproducibility in our work."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Debugging\n",
    "\n",
    "(based on Jessica Hamrick's [debugging demo](https://github.com/jhamrick/nbgrader-demo))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Debugging is one of the most critical tools we have at our disposal.  Apart from standard inspection approaches (`print` statements) the Jupyter notebook has a number of ways to debug as well.\n",
    "\n",
    "Jupyter notebooks provide an interface to the python debugger `pdb`.  The easiest way to use this functionality is by using the \"magic\" `%pdb` at the top of your notebook which will allow cause the notebook to jump into the python debugger anytime an exception is reached.  This will allow you to step through your code and figure out what is wrong.  If you want to step through code or just activate the trace back for the current cell use the `%debug` magic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# for inline plotting in the notebook\n",
    "%matplotlib inline \n",
    "\n",
    "# debugger\n",
    "%pdb\n",
    "\n",
    "import numpy\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def plot_log():\n",
    "    figure, axis = plt.subplots(2, 1)\n",
    "    x = numpy.linspace(1, 2, 10)\n",
    "    axis.plot(x, np.log(x)) # <-- this line is wrong in multiple ways\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "#plot_log()  # Call the function, generate plot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Paths to debugging\n",
    "1. Check the traceback\n",
    "1. Use the `%debug` magic\n",
    "1. `print` statements\n",
    "\n",
    "and if all else fails\n",
    "1. Copy and paste your error message into Google to see if anyone else has experienced similar problems. You'd be surprised how often this works!\n",
    "2. Search [StackOverflow](https://stackoverflow.com/questions/tagged/python)\n",
    "3. Consult fellow classmates\n",
    "4. Consult the TA's and Professor (absolute last resort ;^)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Don't forget to have fun...\n",
    "\n",
    "Debugging is puzzle solving...the better you get at it,  the better you can manage the frustration of numerical methods"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  },
  "latex_envs": {
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 0
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
